package it.uniroma2.editor.extension;

import it.uniroma2.structure.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.w3c.dom.Element;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxMultiplicity;

public class ServiceMultiplicity extends mxMultiplicity{

	private ServiceMultiplicity(boolean source, String type, String attr,
			String value, int min, String max,
			Collection<String> validNeighbors, String countError,
			String typeError, boolean validNeighborsAllowed) {
		super(source, type, attr, value, min, max, validNeighbors, countError,
				typeError, validNeighborsAllowed);
	}
	
	
	public ServiceMultiplicity(boolean source, Service toBeVerified, int min, String max,
			Collection<Service> validNeighbors, String countError,
			String typeError, boolean validNeighborsAllowed) {
		this(source, toBeVerified.getName(), null, null, min, max, getServiceName(validNeighbors), countError,
				typeError, validNeighborsAllowed);
		
	}
	
	
	private static ArrayList<String> getServiceName(Collection<Service> validNeighbors){
		ArrayList<String> validServiceNames = new ArrayList<String>();
		if(validNeighbors == null) return null;
		for(Service valid : validNeighbors){
			validServiceNames.add(valid.getName());
		}
		return validServiceNames;
	}
	
	
	@Override
	public String check(mxGraph graph, Object edge, Object source,
			Object target, int sourceOut, int targetIn) {
		StringBuffer error = new StringBuffer();
//		if(source instanceof Service){
//			System.out.println(((mxCell)source).getValue().toString() + "   sourceOut  :  " + sourceOut + "   targetIn  :  " + targetIn);
//			System.out.println("Min : " + min);System.out.println();
//		}
		
		if ((this.source && checkTerminal(graph, source, edge))
				|| (!this.source && checkTerminal(graph, target, edge)))
		{
			if (!isUnlimited())
			{
				int m = getMaxValue();
//				System.out.println("Max : " + m + "   Min : " + min + "  source : " + this.source + "  archi uscenti : " + sourceOut);

				if (m == 0 || (this.source && (sourceOut >= m))
						|| (!this.source && (targetIn >= m)))
				{
					error.append(countError + "\n");
				}
			}

			if (validNeighbors != null && typeError != null && validNeighbors.size() > 0)
			{
				boolean isValid = checkNeighbors(graph, edge, source, target);

				if (!isValid)
				{
					error.append(typeError + "\n");
				}
			}
		}

		return (error.length() > 0) ? error.toString() : null;
	}
	
	
	@Override
	/**
	 * Checks the type of the given value.
	 */
	public boolean checkNeighbors(mxGraph graph, Object edge, Object source,
			Object target)
	{
		mxIGraphModel model = graph.getModel();
		Object sourceValue = model.getValue(source);
		Object targetValue = model.getValue(target);
		
		System.out.println();
		System.out.println("Source value : " + sourceValue.toString());
		System.out.println("Target value : " + targetValue.toString());
		System.out.println("sorgente : " + this.source);
		
		
		boolean isValid = !validNeighborsAllowed;
		Iterator<String> it = validNeighbors.iterator();

		while (it.hasNext())
		{
			String tmp = it.next();
			System.out.println("Iter valid : " + tmp);
			if (this.source && checkType(graph, targetValue, tmp))
			{
				isValid = validNeighborsAllowed;
				break;
			}
			else if (!this.source && checkType(graph, sourceValue, tmp))
			{
				isValid = validNeighborsAllowed;
				break;
			}
		}
		System.out.println();
		return isValid;
	}

	
	@Override
	/**
	 * Checks the type of the given value.
	 */
	public boolean checkTerminal(mxGraph graph, Object terminal, Object edge)
	{
		Object userObject = graph.getModel().getValue(terminal);

		return checkType(graph, userObject, type, attr, value);
	}
	
	@Override
	/**
	 * Checks the type of the given value.
	 */
	public boolean checkType(mxGraph graph, Object value, String type)
	{
		return checkType(graph, value, type, null, null);
	}

	
	
	@Override
	public boolean checkType(mxGraph graph, Object value, String type,
			String attr, String attrValue) {
		if (value != null)
		{
			if (value instanceof Element)
			{
				return mxUtils.isNode(value, type, attr, attrValue);
			}
			else if(value instanceof Service)
			{
				return type.equals(((Service) value).getName());
			}
			else
			{
				return value.equals(type);
			}
		}

		return false;
	}
}
